2

I'm struggling to find a way to use function from within a wxPython event handler function. Say I have a button that when clicked it runs a function called OnRun using an event handler. However, the user forgot to click a RadionButton before the OnRun button and I want to pop-up a MessageDialog telling them they forgot a step. I'm going to reuse this MessageDialog several times, thus rather than doing a copy/paste of the same code I would like to just have this MessageDialog in a function and call this MessageDialog function if the user forgets to check a RadioButton.

If this wasn't a function used in an Event Handler I know I could simply put the function as an argument but I'm not seeing a way I can do this with these. Any help here would be appreciated.

3 Answers 3

1

The following code shows how to create a little method that you can reuse to show custom dialogs and tells the user that they need to accept the agreement. You can change the conditionals to do whatever you want, of course. And you can change the "showMsg" method so that the icon changes too with just a little tweaking.

import wx

########################################################################
class TestFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="Test")

        panel = wx.Panel(self)
        self.radios = wx.RadioBox(panel, label="Choices",
                                  choices = ["None", "Accept", "Reject"])

        button = wx.Button(panel, label="Run")
        button.Bind(wx.EVT_BUTTON, self.onBtn)

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.radios, 0, wx.ALL, 5)
        sizer.Add(button, 0, wx.ALL, 5)
        panel.SetSizer(sizer)

    #----------------------------------------------------------------------
    def onBtn(self, event):
        """"""
        btn = event.GetEventObject()
        btn.SetLabel("Running")
        radio_value = self.radios.GetStringSelection()
        if radio_value == "None":
            self.showMsg("Error", "Please Choose 'Accept' or 'Reject'!")
        elif radio_value == "Accept":
            self.showMsg("Message", "Thank you for accepting!")
        else:
            self.showMsg("Message", "We're sorry, but you cannot continue the install")

    #----------------------------------------------------------------------
    def showMsg(self, title, msg):
        """"""
        dlg = wx.MessageDialog(None, msg, title, wx.OK | wx.ICON_QUESTION)
        dlg.ShowModal()
        dlg.Destroy()



if __name__ == "__main__":
    app = wx.App(False)
    frame = TestFrame()
    frame.Show()
    app.MainLoop()
Sign up to request clarification or add additional context in comments.

1 Comment

thanks for the answer. I should have went the RadioBox route to start with. This eliminates my other issue of dealing with how to handle when no Radio Buttons are selected. The RadioBox, has the first selected by default which I think works fine for me.
1

I will make a stab at this, even if the answer seems too direct. I would set a property in the enclosing frame that flags whether the Radio Button has been clicked or not. Then when OnRun is called check that property. Should it be in the wrong state, call the MessageDialog and abort/pause/modify the OnRun.

EDIT Here is what I mean, a trivial example with two buttons, neither of which will lead to further action unless a user agreement is clicked.

import wx

class ButtonFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'Button Example', 
                          size=(300, 100))
        panel = wx.Panel(self, -1)
        self.radio = wx.RadioButton(panel, -1, "Accept user agreement", pos=(50, 10))
        self.button = wx.Button(panel, -1, "Run", pos=(50, 30))
        self.Bind(wx.EVT_BUTTON, self.OnRun, self.button)
        self.button.SetDefault()
        self.btn2 = wx.Button(panel, -1, "Walk", pos=(150, 30))
        self.Bind(wx.EVT_BUTTON, self.OnWalk, self.btn2)

    def OnRun(self, event):
        if not self.CheckRadio():
            return
        self.button.SetLabel("Running")

    def OnWalk(self, event):
        if not self.CheckRadio():
            return
        self.btn2.SetLabel("Walking")

    def CheckRadio(self):
        accepted = self.radio.GetValue()
        if not accepted:
            dlg = wx.MessageDialog(None, 'First accept the user agreement',
                                  'MessageDialog', wx.OK | wx.ICON_QUESTION)
            result = dlg.ShowModal() # result not used in this demo
            dlg.Destroy()
            return False
        else:
            return True

if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = ButtonFrame()
    frame.Show()
    app.MainLoop()

Code is adapted from Listing 7.11 of wxPython in Action. I hope this helps, if you have not already solved this n the time that has passed.

1 Comment

thanks for the reply. I am pretty new to python programming so I'm not totally following what you are suggesting. Any chance you could add some example code on how you would do this?
0

You can create your own MessageDialog (inheriting), or you can use functools.partial/lambda to pass an additional argument to the event handler:

self.Bind(wx.MY_EVENT, lambda evt: self.OnEventX(evt, handler=foo), id=12)

1 Comment

So would evt and the foo be the 2 different functions? Like handler=foo would be the OnRun function and the evt would function that calls the MessageDialog?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.